#include <iostream>
#include <map>
#include <iomanip>
#include <vector>
#include <string>
 
typedef std::vector< std::string > Row;
enum Alignment { LEFT, RIGHT }; 
class TextTable {
 
    public:
    TextTable( char horizontal = '-', char vertical = '|', char corner = '+' ) :
        _horizontal( horizontal ),
        _vertical( vertical ),
        _corner( corner )
    {}
 
    unsigned Calsetw(unsigned show_width, const std::string& str) const {
        unsigned width = GetWidth(str);
        return str.size() + show_width - width;
    }
 
    void SetAlignment( unsigned i, Alignment alignment )
    {
        _alignment[ i ] = alignment;
    }
 
    Alignment GetAlignment( unsigned i ) const
    { return _alignment[ i ]; }
 
    char Vertical() const
    { return _vertical; }
 
    char Horizontal() const
    { return _horizontal; }
 
    void Add( std::string const & content )
    {
        _current.push_back( content );
    }
 
    void EndOfRow()
    {
        _rows.push_back( _current );
        _current.assign( 0, "" );
    }
 
    template <typename Iterator>
    void AddRow( Iterator begin, Iterator end )
    {
        for(Iterator i = begin; i != end; ++i ) {
           add( * i ); 
        }
        EndOfRow();
    }
 
    template <typename Container>
    void AddRow( Container const & container )
    {
        AddRow( container.begin(), container.end() );
    }
 
    std::vector< Row > const & Rows() const
    {
        return _rows;
    }
 
    void Setup() const
    {
        DetermineWidths();
        SetupAlignment();
    }
 
    std::string Ruler() const
    {
        std::string result;
        result += _corner;
        for( std::vector<unsigned>::iterator width = _width.begin(); width != _width.end(); ++ width ) {
            result += Repeat( * width, _horizontal );
            result += _corner;
        }
 
        return result;
    }
 
    std::vector<Row> GetRows() const {
        return _rows;
    }
 
    int Width( unsigned i ) const
    { return _width[ i ]; }
 
    private:
    char _horizontal;
    char _vertical;
    char _corner;
    Row _current;
    std::vector< Row > _rows;
    std::vector< unsigned > mutable _width;
    //std::vector< unsigned > _width;
    std::map< unsigned, Alignment > mutable _alignment;
 
    static std::string Repeat( unsigned times, char c )
    {
        std::string result;
        for( ; times > 0; -- times )
            result += c;
 
        return result;
    }
   
 
    unsigned GetWidth(const std::string &str) const {
        unsigned width = 0;
        size_t i = 0;
        while(i < str.size()) {
            if (str[i] >= 0 && str[i] <= 127) {
                width += 1;
                ++i;
            }   
            else {
                width += 2;
                i += 3;
            }   
        }   
        return width;
    }
 
    unsigned Columns() const
    {
        if (_rows.size() > 0) {
            return _rows[ 0 ].size();
        }
        else {
            return 0;
        }
    }
 
    void DetermineWidths() const
    {
        _width.assign( Columns(), 0 );
        for ( std::vector<Row>::const_iterator rowIterator = _rows.begin(); rowIterator != _rows.end(); ++ rowIterator ) {
            Row const & row = * rowIterator;
            for ( unsigned i = 0; i < row.size(); ++i ) {
                //_width[ i ] = _width[ i ] > row[ i ].size() ? _width[ i ] : row[ i ].size();
                unsigned row_width = GetWidth(row[i]);
                _width[ i ] = _width[ i ] > row_width ? _width[ i ] : row_width;
            }
        }
    }
 
    void SetupAlignment() const
    {
        for ( unsigned i = 0; i < Columns(); ++i ) {
            if ( _alignment.find( i ) == _alignment.end() ) {
                _alignment[ i ] = LEFT;
            }
        }
    }
};
 
std::ostream & operator<<( std::ostream & stream, TextTable const & table )
{
    table.Setup();
    stream << table.Ruler() << "\n";
    std::vector<Row> rows = table.GetRows();
    for (size_t i = 0; i < rows.size(); ++i) {
        Row row = rows[i];
        stream << table.Vertical();
        for (size_t j = 0; j < row.size(); ++j) {
            //stream << std::setw( table.width( j ) ) << std::right << row[ j ];
            stream << std::setw( table.Calsetw(table.Width(j), row[j])) << std::right << row[ j ];
            stream << table.Vertical();
        }
        stream << "\n";
        stream << table.Ruler() << "\n";
    }
 
    return stream;
}
 
/*
 int main() {
 TextTable t( '-', '|', '+' );
 t.Add( "" );
 t.Add( "Sex" );
 t.Add( "Age" );
 t.EndOfRow();
 t.Add( "Moses" );
 t.Add( "male" );
 t.Add( "4556" );
 t.EndOfRow();
 std::cout << t;
 }
 */
